//
//  GYXStatusListViewModel.swift
//  GYXWeibo
//
//  Created by Twisal on 2017/1/17.
//  Copyright © 2017年 Twisal. All rights reserved.
//

import Foundation
import SDWebImage
// 设置允许最大的上拉刷新次数
fileprivate let maxPullupTryTimes = 3

/// 微博数据列表视图模型
/*
 父类的选择
 
 - 如果类需要使用 `KVC` 或者字典转模型框架设置对象值，类就需要继承自 NSObject
 - 如果类只是包装一些代码逻辑(写了一些函数)，可以不用任何父类，好处：更加轻量级
 - 提示：如果用 OC 写，一律都继承自 NSObject 即可
 
 使命：负责微博的数据处理
 1. 字典转模型
 2. 下拉／上拉刷新数据处理
 */
class GYXStatusListViewModel {
    /// 设置上拉刷新错误次数
    var pullupErrorTimes = 0
    
    /// 懒加载微博数组
    lazy var statusList = [GYXStatusViewModel]()
    
    /// 加载微博数据列表
    ///
    /// - Parameters:
    ///   - pullup: 是否上拉刷新
    ///   - completion: 完成回调
    func loadStatus(pullup: Bool, completion: @escaping (_ isSuccess: Bool, _ shouldRefresh: Bool) -> ()) {
        
        if pullup && pullupErrorTimes > maxPullupTryTimes {
            completion(true, false)
            return
        }
        // 下拉刷新
        let since_id = pullup ? 0 : (statusList.first?.status.id ?? 0)
        // 上拉刷新
        let max_id = !pullup ? 0 : (statusList.last?.status.id ?? 0)
        GYXNetworkManager.shared.loadStatusList(since_id: since_id, max_id: max_id) { (list, isSuccess) in
            // 0, 判断是否请求成功
            if !isSuccess {
                // 直接回调
                completion(false, false)
                return
            }
            
            // 1, 字典转模型
            // 视图模型的可变数组
            var array = [GYXStatusViewModel]()
            // 遍历请求后返回的字典数组
            for dict in list ?? [] {
                // 1> 创建模型
                let status = GYXStatus()
                // 2> 字典转模型, 如果失败继续
                status.yy_modelSet(with: dict)
                // 3>通过构造函数创建视图模型,并添加到视图模型数组中
                array.append(GYXStatusViewModel(model: status))
            }
            
            print(array)
            
            // 2, 加载数据
            if pullup {
                // 上拉刷新将数据添加到后面
                self.statusList += array
            } else {
                // 下拉刷新将数据添加到前面
                self.statusList = array + self.statusList
            }
            
            // 3, 判断是否需要上拉刷新
            if pullup && array.count == 0 {
                self.pullupErrorTimes += 1
                completion(isSuccess, false)
                
            } else {
                // 缓存单张图片
                self.cacheSinglePicture(list: array, finished: completion)
                // 4, 真正有数据的回调！
                completion(isSuccess, true)
            }
        }
        
    }
    
    /// 缓存只有单张图片微博中的图片
    ///
    /// - Parameter list: viewModel的数组
    private func cacheSinglePicture(list: [GYXStatusViewModel], finished: @escaping (_ isSuccess: Bool, _ shouldRefresh: Bool) -> ()) {
        
        // 创建调度组
        let group = DispatchGroup()
        // 记录数据长度
        var length = 0
        
        for vm in list {
            // 查看配图中的图片数量
            if vm.picUrls?.count != 1 {
                continue
            }
            
            guard let urlStr = vm.picUrls?[0].thumbnail_pic,
                let url = URL(string: urlStr) else {
                    continue
            }
            // 3> 下载图像
            // 1) downloadImage 是 SDWebImage 的核心方法
            // 2) 图像下载完成之后，会自动保存在沙盒中，文件路径是 URL 的 md5
            // 3) 如果沙盒中已经存在缓存的图像，后续使用 SD 通过 URL 加载图像，都会加载本地沙盒地图像
            // 4) 不会发起网路请求，同时，回调方法，同样会调用！
            // 5) 方法还是同样的方法，调用还是同样的调用，不过内部不会再次发起网路请求！
            // *** 注意点：如果要缓存的图像累计很大，要找后台要接口！
            
            // A> 入组
            group.enter()
            SDWebImageManager.shared().downloadImage(with: url, options: [], progress: nil, completed: { (image, _, _, _, _) in
                // 将图像转换成二进制数据
                if let image = image,
                    let data = UIImagePNGRepresentation(image) {
                     // NSData 是 length 属性
                    length += data.count
                    // 图像缓存成功，更新配图视图的大小
                    vm.updateSingleImageSize(image: image)
                }
                print("缓存的图像是 \(image) 长度 \(length)")
                // B> 出组 - 放在回调的最后一句
                group.leave()
            })
            
        }
        
        // C> 监听调度组情况
        group.notify(queue: DispatchQueue.main, execute: {
            print("图像缓存完成 \(length / 1024) K")
            finished(true, true)
        })
    }
    
   
}
